#include "incs.h"

#include "EventManager.h"


const char * const EventManager::kpWildcardEventType = "*";


bool EventManager::AddListener( IEventListener::Ptr const & listener, 
							   EventType const & type )
{
	if ( ! ValidateType( type ) )
		return false;

	// check / update type list

	EventTypeSet::iterator evIt = mTypeSet.find( type );

	if ( evIt == mTypeSet.end() )
	{
		// was not in the list, add it ...

		EventTypeSetIRes ires = mTypeSet.insert( type );

		// insert failed for some reason
		if ( ires.second == false )
			return false;

		// somehow we inserted and left the list empty!?!?!
		if ( ires.first == mTypeSet.end() )
			return false;

		evIt = ires.first; // store for later use
	}

	// find listener map entry, create one if no table already
	// exists for this entry ...

	EventListenerMap::iterator elmIt =
		mRegistry.find( type.GetIdent() );

	if ( elmIt == mRegistry.end() )
	{
		EventListenerMapIRes elmIRes = mRegistry.insert(
			EventListenerMapEnt( type.GetIdent(),
			EventListenerTable() ) );

		// whoops, could not insert into map!?!?
		if ( elmIRes.second == false )
			return false;

		// should not be possible, how did we insert and create
		// an empty table!?!?!
		if ( elmIRes.first == mRegistry.end() )
			return false;

		// store it so we can update the mapped list next ...
		elmIt = elmIRes.first;

	}

	// update the mapped list of listeners, walk the existing
	// list (if any entries) to prevent duplicate addition of
	// listeners. This is a bit more costly at registration time
	// but will prevent the hard-to-notice duplicate event
	// propogation sequences that would happen if double-entries
	// were allowed.

	// note: use reference to make following code more simple
	EventListenerTable & evlTable = (*elmIt).second;

	for ( EventListenerTable::iterator it = evlTable.begin(),
		itEnd = evlTable.end(); it != itEnd ; it++ )
	{
		bool bListenerMatch = ( *it == listener );

		if ( bListenerMatch )
			return false;
	}

	// okay, event type validated, event listener validated,
	// event listener not already in map, add it

	evlTable.push_back( listener );

	return true;
}



EventManager::EventManager( char const * const name )
: IEventManager(name), mActiveQueue(0)
{
}

EventManager::~EventManager()
{
	mActiveQueue = 0;
}

bool EventManager::RemListener( IEventListener::Ptr const & listener, 
							   EventType const & type )
{
	if ( ! ValidateType( type ) )
		return false;

	bool rc = false;

	// brute force method, iterate through all existing mapping
	// entries looking for the matching listener and remove it.

	for ( EventListenerMap::iterator it = mRegistry.begin(),
		itEnd = mRegistry.end(); it != itEnd; it++ )
	{
		unsigned int const    kEventId = it->first;
		EventListenerTable & table    = it->second;

		for ( EventListenerTable::iterator it2 = table.begin(),
			it2End = table.end(); it2 != it2End; it2++ )
		{
			if ( *it2 == listener )
			{
				// found match, remove from table,
				table.erase( it2 );

				// update return code
				rc = true;

				// and early-quit the inner loop as addListener()
				// code ensures that each listener can only
				// appear in one event's processing list once.
				break;
			}
		}
	}

	return rc;
}

bool EventManager::Trigger( Event const & ev ) const
{
	if ( ! ValidateType( ev.GetType() ) )
		return false;

	EventListenerMap::const_iterator itWC = mRegistry.find( 0 );

	if ( itWC != mRegistry.end() )
	{
		EventListenerTable const & table = itWC->second;

		bool processed = false;

		for ( EventListenerTable::const_iterator it2 = table.begin(),
			it2End = table.end(); it2 != it2End; it2++ )
		{
			(*it2)->HandleEvent( ev );
		}
	}

	EventListenerMap::const_iterator it =
		mRegistry.find( ev.GetType().GetIdent() );

	if ( it == mRegistry.end() )
		return false;

	EventListenerTable const & table = it->second;

	bool processed = false;

	for ( EventListenerTable::const_iterator it2 = table.begin(),
		it2End = table.end(); it2 != it2End; it2++ )
	{
		if ( (*it2)->HandleEvent( ev ) )
		{
			// only set to true, if processing eats the messages
			processed = true;
		}
	}

	return processed;
}

bool EventManager::QueueEvent( Event::Ptr const & ev )
{
	assert ( mActiveQueue >= 0 );
	assert ( mActiveQueue < kNumQueues );

	if ( ! ValidateType( ev->GetType() ) )
		return false;

	EventListenerMap::const_iterator it =
		mRegistry.find( ev->GetType().GetIdent() );

	if ( it == mRegistry.end() )
	{		
		// if global listener is not active, then abort queue add
		EventListenerMap::const_iterator itWC = mRegistry.find( 0 );

		if ( itWC == mRegistry.end() )
		{
			// no listeners for this event, skipit
			return false;
		}
	}

	mQueues[mActiveQueue].push_back( ev );

	return true;
}

bool EventManager::AbortEvent( EventType const & type, bool all /*= false */ )
{
	assert ( mActiveQueue >= 0 );
	assert ( mActiveQueue < kNumQueues );

	if ( ! ValidateType( type ) )
		return false;

	EventListenerMap::iterator it = mRegistry.find( type.GetIdent() );

	if ( it == mRegistry.end() )
		return false; // no listeners for this event, skipit

	bool rc = false;

	for ( EventQueue::iterator it = mQueues[mActiveQueue].begin(),
		itEnd = mQueues[mActiveQueue].end(); it != itEnd; it++ )
	{
		if ( (*it)->GetType() == type )
		{
			mQueues[mActiveQueue].erase(it);
			rc = true;
			if ( !all )
				break;
		}
	}

	return rc;
}


bool EventManager::Update()
{
	EventListenerMap::const_iterator itWC = mRegistry.find( 0 );

	// swap active queues, make sure new queue is empty after the
	// swap ...

	int queueToProcess = mActiveQueue;

	mActiveQueue = ( mActiveQueue + 1 ) % kNumQueues;

	mQueues[mActiveQueue].clear();

	// now process as many events as we can ( possibly time
	// limited ) ... always do AT LEAST one event, if ANY are
	// available ...

	while ( mQueues[queueToProcess].size() > 0 )
	{
		Event::Ptr event = mQueues[queueToProcess].front();

		mQueues[queueToProcess].pop_front();

		EventType const & eventType = event->GetType();

		EventListenerMap::const_iterator itListeners =
			mRegistry.find( eventType.GetIdent() );

		if ( itWC != mRegistry.end() )
		{
			EventListenerTable const & table = itWC->second;

			bool processed = false;

			for ( EventListenerTable::const_iterator
				it2 = table.begin(), it2End = table.end();
				it2 != it2End; it2++ )
			{
				(*it2)->HandleEvent( *event );
			}
		}

		// no listeners currently for this event type, skipit
		if ( itListeners == mRegistry.end() )
			continue;

		unsigned int const kEventId = itListeners->first;
		EventListenerTable const & table = itListeners->second;

		for ( EventListenerTable::const_iterator
			it = table.begin(), end = table.end();
			it != end ; it++ )
		{
			if ( (*it)->HandleEvent( *event ) )
			{
				break;
			}
		}


	}

	// if any events left to process, push them onto the active
	// queue.
	//
	// Note: to preserver sequencing, go bottom-up on the
	// raminder, inserting them at the head of the active
	// queue...

	bool queueFlushed = ( mQueues[queueToProcess].size() == 0 );

	if ( !queueFlushed )
	{
		while ( mQueues[queueToProcess].size() > 0 )
		{
			Event::Ptr event = mQueues[queueToProcess].back();

			mQueues[queueToProcess].pop_back();

			mQueues[mActiveQueue].push_front( event );
		}
	}

	// all done, this pass

	return queueFlushed;
}

bool EventManager::ValidateType( EventType const & type ) const
{
	if ( type.GetIdentStr() == NULL )
		return false;

	if ( ( type.GetIdent() == 0 ) &&
		(strcmp(type.GetIdentStr(),kpWildcardEventType) != 0) )
		return false;

	EventTypeSet::const_iterator evIt =
		mTypeSet.find( type );

	if ( evIt != mTypeSet.end() )
	{
		// verify that the text signature is the same as already
		// known ...

		EventType const & known = *evIt;

		char const * const kKnownTag = known.GetIdentStr();
		char const * const kNewTag   = type.GetIdentStr();

		int cv = _stricmp( kKnownTag, kNewTag );

		// tag mismatch for ident value, not accepted
		if ( cv != 0 )
			return false;
	}

	return true;
}

EventListenerList EventManager::GetListenerList( EventType const & type ) const
{
	// invalid event type, so sad
	if ( ! ValidateType( type ) )
		return EventListenerList();

	EventListenerMap::const_iterator itListeners =
		mRegistry.find( type.GetIdent() );

	// no listerners currently for this event type, so sad
	if ( itListeners == mRegistry.end() )
		return EventListenerList();

	EventListenerTable const & table = itListeners->second;

	// there was, but is not now, any listerners currently for
	// this event type, so sad
	if ( table.size() == 0 )
		return EventListenerList();

	EventListenerList result;

	result.reserve( table.size() );

	for ( EventListenerTable::const_iterator it = table.begin(),
		end = table.end(); it != end ; it++ )
	{
		result.push_back( *it );
	}

	return result;
}

EventTypeList EventManager::GetTypeList() const
{
	// no entries, so sad
	if ( mTypeSet.size() == 0 )
		return EventTypeList();

	EventTypeList result;

	result.reserve( mTypeSet.size() );

	for ( EventTypeSet::const_iterator it = mTypeSet.begin(),
		itEnd = mTypeSet.end(); it != itEnd; it++ )
	{
		result.push_back( *it );
	}

	return result;
}